#include "performanceTest.h"

#define IMAGE_LIST_FILENAME "imageList.txt"
#define RESULTS_TEXT_FILENAME "results.txt"
#define RESULTS_MATRIX_FILENAME "results.yml"

//naiveConvolution.h
#define NAIVE 0
#define NAIVE_PTR 1
//separatedConvolution.h
#define SEPARATED 2
#define SEPARATED_PTR 3
//symmetricKernConvolution.h
#define SYMMETRIC 4
//integralImageConvolution.h
#define INTEGRAL 5
#define INTEGRAL_PTR 6
//fourierConvolution.h
#define FFT 7

#define OPENCVCONV 8


#define DIM5 0
#define DIM25 1
#define DIM45 2
#define DIM65 3
#define DIM85 4
#define DIM105 5
#define DIM125 6
#define DIM145 7
#define DIM165 8
#define DIM185 9
#define DIM205 10
#define DIM225 11

#define N_ALG 9 //numero dei metodi utilizzati
#define N_KER 12//numero di kernel

#ifndef TIMECALC
#define TIMECALC
#include <time.h>
#include "timeCalc.h"
#endif

/** Funzione per dato il nome del metodo di convoluzione che si vuole utilizzare
 * chiama la funzione corrispondente
 * @param image immagine su cui applicare il filtro
 * @param dimKer dimensione del kernel che si vuole applicare
 * @param nomeAlg algoritmo da applicare
 */
int useAlgorithm(int ALG,Mat1b& image, int dimKer,string& nomeAlg){
	float sigma = 0.9f;
	//Kernel Gaussiano
	Mat_<float> kernel = getGaussianKernel(dimKer,sigma) * getGaussianKernel(dimKer,sigma).t();
	Mat1b out(image.rows,image.cols);
	switch(ALG){
		case NAIVE:			naiveConvolution(image,out,kernel);
							nomeAlg = "Naive Convolution: ";
							break;
		case NAIVE_PTR:		naiveConvWithPointers(image.data ,image.rows, image.cols, out.data,(float*)kernel.data,kernel.rows,kernel.cols);
							nomeAlg = "Naive Convolution with Pointers: ";
							break;
		case SEPARATED:		separatedConvolution(image,out,kernel);
							nomeAlg = "Separated Convolution: ";
							break;
		case SEPARATED_PTR:	separatedConvWithPointers(image,out,kernel);
							nomeAlg = "Separated Convolution with Pointers: ";
							break;
		case SYMMETRIC:		simpleSymmetricKernConv(image,kernel,out);
							nomeAlg = "Simmetric Convolution: ";
							break;
		case INTEGRAL:		integralImgGaussianConv(image,out,sigma);
							nomeAlg = "Integral Convolution: ";
							break;
		case INTEGRAL_PTR:	integralImgGaussianConvPoint(image,out,sigma);
							nomeAlg = "Integral Convolution with Pointers: ";
							break;
		case FFT:			fourierConvolution(image,out,kernel,1);
							nomeAlg = "Fast Fourier Transform Convolution: ";
							break;
		case OPENCVCONV:	cvConvolution(image,kernel,out);
							nomeAlg = "OPENCV Convolution: ";
							break;
	}
	kernel.release();
	return 0;
}

/** Legge gli url delle immagini da testare da file e li carica in un vector
 * @param fpath path del file contenente gli url delle immagini
 * @param imageSet struttura dati contenente gli url delle immagini
 */
void readImageList(string fpath, vector<string> &imageSet ){
	
	ifstream in(fpath.c_str(), ios::in);
	if(!in){
		cout << "Errore apertura file " << fpath.c_str() << endl;
        return;
	}	
	string s;
	while (true){	
		in >> s;
		if(in.eof())
			break;		
		imageSet.push_back(s);
	}
	in.close();
}


/** Esegue il test delle performance di tutti gli algoritmi realizzati */
int test(){
	//Matrice dei risultati
	Mat_<double> results(N_ALG,N_KER);
	
	//Path delle immagini
	vector<string> imageName;

	//Caricare il data set
	readImageList(IMAGE_LIST_FILENAME,imageName);
	
	//Salvataggio dei risultati
	fstream ftmp(RESULTS_TEXT_FILENAME,ios::out);
	if(!ftmp){
		cout << "Errore apertura file\n " << RESULTS_TEXT_FILENAME;
	}	

	ofstream out("result_grafico.txt", ios::out);
	if(!out.is_open()){ cout << "errore apertura result_grafico.txt\n";}

#ifdef DEBUG_ON
	for(unsigned i = 0 ; i < imageName.size() ; ++i)
		cout << imageName[i] << endl;
#endif

	//per ogni funzione e per ogni elemnto del vettore dobbiamo
	Mat1b image;		//processed image
	clock_t startTime;	//timer
	double timeR;		//execution time
	string nomeAlg = "";
	cout << "attendere" << endl;
	//Per ogni algoritmo 
	for(int alg = NAIVE_PTR ; alg < N_ALG ; ++alg){
		
		//Per ogni dimensione del kernel
		for(int size = DIM5 ; size < N_KER ; ++size){
			
            int ksize = (size*20)+5;
            
            //Faccio partire il tempo
			startTime = clock();
			//Calcoliamo il tempo di esecuzione della convoluzione di tutto il dataset
			//per minimizzare gli errori
			for(vector<string>::iterator i = imageName.begin() ; i != imageName.end(); ++i){
				//Leggo l'immagine in bianco e nero
                //cout << *i ;
				image = imread(*i,0);
                //imshow("image", image);
                //waitKey();
				useAlgorithm(alg,image, ksize,nomeAlg);
				cout << ".";
			}
			//fermo il timer
			timeR = double( clock() - startTime ) / (double)CLOCKS_PER_SEC;
			//salviamo i tempi nella matrice result
			results(alg,size) = timeR;

			cout << endl << nomeAlg << timeR << " secondi. Kernel: "<< ksize <<"x" << ksize << endl;
			ftmp << nomeAlg << ": " << timeR << "s " << ksize <<"x" << ksize << "\n";
			ftmp.flush();
			image.release();

			//Salvo i dati sul file out
			out << nomeAlg << "," << ksize<< "," << timeR << "\n";
		}
	}
	ftmp.close();
	out.close();
	
	FileStorage fs(RESULTS_MATRIX_FILENAME, FileStorage::WRITE);
    time_t rawtime; time(&rawtime);
    fs << "Data del Test" << asctime(localtime(&rawtime));
	fs << "results" << results;
	fs.release();
	
	//Salvo i tempi di nuovo

	
	
	
	return 0;
}



int TESTFFT_DACANCELLARE(){
	
	Mat_<Vec3b> inImg1 = imread("Sun4/desert/sun_acxdijcmkawhkhob.jpg");
	Mat_<uchar> inImg(inImg1.rows,inImg1.cols);
	cvtColor(inImg1,inImg,CV_BGR2GRAY);

	//namedWindow( "originale", CV_WINDOW_NORMAL );
	//imshow( "originale", inImg );

	//Immagini di uscita
	Mat_<uchar> outImg(inImg.rows,inImg.cols);
	
	//Kernel
	Mat_<float> kernel = getGaussianKernel(225,0.9f) * getGaussianKernel(225,0.9f).t();
	

	
	clock_t startTime;
	

	//clock_t startTime;
	startTime = clock();
	separatedConvolution(inImg,outImg,kernel);
	cout << "Separated Convolution: "<< double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " secondi." << endl;
	


	startTime = clock();
	cvConvolution(inImg,kernel,outImg);
	cout << "Convoluzione OPENCV: "<< double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " secondi." << endl;
	
	startTime = clock();
	fourierConvolution(inImg,outImg,kernel,1);
	cout << "Convoluzione Fourier: "<< double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " secondi." << endl;
	

	//namedWindow( "risultato", CV_WINDOW_NORMAL );
	//imshow( "risultato", outImg );
	waitKey();
	return 0;

}
